package cn.juforg.airled;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class AirView extends SurfaceView implements SurfaceHolder.Callback{

	int matrixSize = 16;						//字模的size
	int sum = (matrixSize * matrixSize / 8); 	//单个自摸所占字节数
	String text="";						//要显示的字符串
	private byte[][] ScreenMatrix;		//整个屏幕的矩阵 高为size
	private short[][] actualMatrix;
	private int gridSize;				//格子大小
	private int xCount;					//屏幕横向格子数
	private int xOffset;				//横向偏移量
	Paint paint = new Paint();	//画笔对象
	private File fontFile;				//字库文件
	Paint textPaint = new Paint();  
	List<byte[]> byteList = new ArrayList<byte[]>();//字符串的点阵list
	Bitmap[] GridBitMap = new Bitmap[2];
	Drawable gridPicture;
	SurfaceHolder surfaceHolder;
	
	
	public void setText(String text) {
		this.text = text;
	}

	public AirView(Context context) {
		super(context);
	}
	
	public AirView(Context context, int matrixSize, String text,
			DisplayMetrics metric, Paint paint, Drawable gridPicture, File fontFilePath) throws UnsupportedEncodingException, IOException {
		super(context);
		this.matrixSize = matrixSize;
		this.sum = (matrixSize * matrixSize / 8);
		this.text = text;
		this.gridSize = metric.heightPixels/matrixSize;
		this.xCount = metric.widthPixels/gridSize;
		this.xOffset = (metric.widthPixels-gridSize*xCount)/2;
		this.ScreenMatrix = new byte[xCount][matrixSize];
		this.paint = paint;
		this.paint.setColor(Color.WHITE);
		this.gridPicture = gridPicture;
		this.fontFile = fontFilePath;
		textPaint.setColor(Color.WHITE);        //设置画笔颜色  
		textPaint.setAlpha(255);          //设置透明度  
		textPaint.setStyle(Paint.Style.FILL);  
		textPaint.setAntiAlias(true); 
//		getMatrixByteList(this.text);
//		generateGridBitMap(GridBitMap, paint, gridPicture, gridSize);
//		genActualMatrixShortList();
		this.surfaceHolder = this.getHolder();//获取holder
		surfaceHolder.addCallback(this);
//		startUI();
	}

	public void init() throws UnsupportedEncodingException, IOException{
		getMatrixByteList(this.text);
		generateGridBitMap(GridBitMap, paint, gridPicture, gridSize);
		genActualMatrixShortList();
	}

	/**
	 * 
	 * 计算机处理汉字信息的前提条件是对每个汉字进行编码，这些编码统称为汉字编码。汉字信息在系统内传送的过程就是汉字编码转换的过程。
	 * 汉字交换码：汉字信息处理系统之间或通信系统之间传输信息时，对每一个汉字所规定的统一编码，
	 * 我国已指定汉字交换码的国家标准“信息交换用汉字编码字符集——基本集”，代号为GB
	 * 2312—80，又称为“国标码”。
	 * 国标码：所有汉字编码都应该遵循这一标准，汉字机内码的编码、汉字字库的设计、汉字输入码的转换、输出设备的汉字地址码等，都以此标准为基础。GB2312—80就是国标码。
	 * 该码规定：一个汉字用两个字节表示，每个字节只有7位，与ASCII码相似。
	 * 区位码：将GB2312—80的全部字符集组成一个94×94的方阵，每一行称为一个“区”，编号为0l～94；每一列称为一个“位”，编号为0l～94，这样得到GB2312—80的区位图，
	 * 用区位图的位置来表示的汉字编码，称为区位码。
	 * 机内码：为了避免ASCII码和国标码同时使用时产生二义性问题，大部分汉字系统都采用将国标码每个字节高位置1作为汉字机内码。
	 * 这样既解决了汉字机内码与西文机内码之间的二义性，又使汉字机内码与国标码具有极简单的对应关系。
	 * 汉字机内码、国标码和区位码三者之间的关系为：区位码（十进制）的两个字节分别转换为十六进制后加20H得到对应的国标码；
	 * 机内码是汉字交换码（国标码）两个字节的最高位分别加1，即汉字交换码（国标码）的两个字节分别加80H得到对应的机内码；
	 * 区位码（十进制）的两个字节分别转换为十六进制后加A0H得到对应的机内码。
	 * @param gb2312Str
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	public void getMatrixByteList(String gb2312Str)
			throws UnsupportedEncodingException, IOException {
		byteList.clear();
		if (null == gb2312Str.trim() || "".equals(gb2312Str.trim())) {
			return ;
		}
		
		RandomAccessFile raf = null;
		InputStream is = null;
		FileOutputStream fos = null;
//		File path = new File(Environment.getExternalStorageDirectory(), "AirLED"+File.separator+"font");//存放在存储卡中
		File file = fontFile;
		try {
			/*byte readBuff[] = new byte[1024];
			if (!path.exists()) {
				path.mkdirs();
			}
			if (!file.exists()) {
					file.createNewFile();
				is = getResources().openRawResource(R.raw.hzk16);
				fos = new FileOutputStream(file.getAbsolutePath());
				int length = -1;
				while ((length = is.read(readBuff)) != -1) {
					fos.write(readBuff);
				}
				
			}*/
			
			raf = new RandomAccessFile(file.getAbsolutePath(), "r");// 随机读取字库文件
			char[] singleGB2312Chars = gb2312Str.toCharArray();
			for (char c : singleGB2312Chars) {
				byte iBuff[] = new byte[matrixSize * 2];// 连续读入
				raf.seek(getOffSet(c));
				raf.read(iBuff);
				if (null!=iBuff) {
					byteList.add(iBuff);
				}
			}

		} finally {
			if (null != is) {
				is.close();
			}
			if (null != fos) {
				fos.close();
			}
			if (null != raf) {
				raf.close();
			}
		}
	}

	public int getOffSet(char cn) throws UnsupportedEncodingException {
		byte data[] = null;
		data = String.valueOf(cn).getBytes("GB2312");
		byte iHigh, iLow;// 高8位，低8位
		iHigh = (byte) (data[1]);
		iLow = (byte) (data[0]);
		int IOffset;// 文件偏移量
		// IOffset = [(低八位-0xa1)*94(十进制)+(高八位-0xa1)]*32(十进制)
		IOffset = (94 * (iLow + 256 - 161) + (iHigh + 256 - 161)) * sum;// +256防止byte值为负
																		// 汉字字模在字库中的偏移地址
		return IOffset;
	}
	/* 
	@Override
	protected void onDraw(Canvas canvas) {
		for (int i = 0; i < xCount; i++) {
			for (int j = 0; j < matrixSize; j++) {
				if (ScreenMatrix[i][j] == 0) {
					canvas.drawBitmap(GridBitMap[ScreenMatrix[i][j]], xOffset + i * gridSize , j * gridSize, paint);
				}else if (ScreenMatrix[i][j] != 0) {
					canvas.drawCircle(xOffset + gridSize/2 + i * gridSize, j * gridSize+gridSize/2, gridSize/2, paint0);
					canvas.drawBitmap(GridBitMap[ScreenMatrix[i][j]], xOffset + i * gridSize , j * gridSize, paint);
				}
			}
		}

	}
	*/
	public void clearScreenMatrix(){
		for (int i = 0; i < xCount; i++) {
			for (int j = 0; j < matrixSize; j++) {
				ScreenMatrix[i][j] = 0;
			}
		}
	}
	
	/**
	 *  生成 用于 显示的 单元格 的bitmap 亮  与  暗 
	 * @param GridBitMap
	 * @param paint
	 * @param gridPicture
	 * @param gridSize
	 */
	public void generateGridBitMap(Bitmap[] GridBitMap, Paint paint, Drawable gridPicture, int gridSize){
		gridPicture.setBounds(0, 0, gridSize, gridSize);
		Bitmap shineBitmap = Bitmap.createBitmap(gridSize, gridSize, Bitmap.Config.ARGB_8888);
		Bitmap dimBitmap = Bitmap.createBitmap(gridSize, gridSize, Bitmap.Config.ARGB_8888);
		
		Canvas shineCanvas = new Canvas(shineBitmap);
		Canvas dimCanvas = new Canvas(dimBitmap);
		gridPicture.draw(shineCanvas);
		gridPicture.draw(dimCanvas);
		GridBitMap[0] = shineBitmap;
		GridBitMap[1] = dimBitmap;
		
	}
	
	/**
	 * 
	 * @param scrollOffset
	 */
	public void refreshScreenMatrix(Long scrollOffset, int orientation){
		this.clearScreenMatrix();
		Log.i("info_airled", "refreshScreenMatrix scrollOffset:"+scrollOffset);
		int x =(int) (scrollOffset%(byteList.size()*matrixSize+xCount));
		Log.i("info_airled", "x:"+x);
		Log.i("info_airled", "xCount:"+xCount);
//		int x =(int) (scrollOffset%xCount);
		for (int t = 0; t < byteList.size() ; t++) {
			for (int i = 0; i < matrixSize; i++) {
				for (int j = 0; j < 2; j++) {
					for (int k = 0; k < 8; k++) {
						try {
							if(((byteList.get(t)[i*2+j])&(0x80>>k))>=1){
								if (xCount-x+t*matrixSize+j*8+k>xCount) {
									break;
								}else if(xCount-x+t*matrixSize+j*8+k<=xCount-1){
									if (xCount-x+t*matrixSize+j*8+k>0) {
										Log.i("info_airled", "123="+(xCount-x+t*matrixSize+j*8+k));
										ScreenMatrix[xCount-x+t*matrixSize+j*8+k][i]=1;
									}
								}else if (t*matrixSize+j*8+k>xCount-1) {
									if (x%(byteList.size() * matrixSize)>xCount) {
										Log.i("info_airled", "asdf="+(xCount-x+t*matrixSize+j*8+k));
										ScreenMatrix[xCount-1-x+t*matrixSize+j*8+k][i]=1;
									}
//									ScreenMatrix[-x+t*matrixSize+j*8+k][i]=1;
								}
							}
						} catch (Exception e) {
							Log.i("info_airled", "t:"+t);
							Log.i("info_airled", "i:"+i);
							Log.i("info_airled", "j:"+j);
							Log.i("info_airled", "k:"+k);
							Log.i("info_airled", "xCount-x+t*matrixSize+j*8+k="+(xCount-x+t*matrixSize+j*8+k));
							Log.i("info_airled", "byteList.get(t).length:"+byteList.get(t).length);
							e.printStackTrace();
							return;
						}
					}
				}
			}
		}
	}
	
	/**
	 * 
	 * @param scrollOffset
	 */
	public void refreshScreenMatrixFromActualMatrix(Long scrollOffset, int orientation){
		this.clearScreenMatrix();
		Log.i("info_airled", "refreshScreenMatrix scrollOffset:"+scrollOffset);
		int xScroll =(int) (scrollOffset%(byteList.size()*matrixSize+xCount));//横向移动个数
		Log.i("info_airled", "xScroll:"+xScroll);
		Log.i("info_airled", "xCount:"+xCount);
//		int x =(int) (scrollOffset%xCount);
		int i = 0;
		int j = 0;
		try {
			canvas = surfaceHolder.lockCanvas();
			canvas.drawColor(Color.BLACK);
			while ( i >= 0 && i < byteList.size()*matrixSize ) {
				if((xOffset + (i+xCount-xScroll-1) * gridSize) > this.getWidth() && orientation == 1){
					break;
				}
       			for ( j = 0; j < matrixSize; j++) {
       				if (actualMatrix[i][j] == 0) {
//       					canvas.drawBitmap(GridBitMap[actualMatrix[i][j]], xOffset + (i+xCount-xScroll-1) * gridSize , j * gridSize, paint);
       				}else if (actualMatrix[i][j] != 0) {
       					canvas.drawCircle(xOffset + gridSize/2 + (i+xCount-xScroll-1) * gridSize, j * gridSize+gridSize/2, gridSize/2, textPaint);
       					canvas.drawBitmap(GridBitMap[actualMatrix[i][j]], xOffset + (i+xCount-xScroll-1) * gridSize , j * gridSize, paint);
       				}
       			}
       			if (orientation == 1 ) {
					i++;
				}else {
					i = byteList.size()*matrixSize;
					i--;
				}
       		}
/*			for ( i = 0; i < byteList.size()*matrixSize ; i++) {
				if((xOffset + (i+xCount-xScroll-1) * gridSize) > this.getWidth()){
					break;
				}
				for ( j = 0; j < matrixSize; j++) {
					if (actualMatrix[i][j] == 0) {
//       					canvas.drawBitmap(GridBitMap[actualMatrix[i][j]], xOffset + (i+xCount-xScroll-1) * gridSize , j * gridSize, paint);
					}else if (actualMatrix[i][j] != 0) {
						canvas.drawCircle(xOffset + gridSize/2 + (i+xCount-xScroll-1) * gridSize, j * gridSize+gridSize/2, gridSize/2, textPaint);
						canvas.drawBitmap(GridBitMap[actualMatrix[i][j]], xOffset + (i+xCount-xScroll-1) * gridSize , j * gridSize, paint);
					}
				}
			}
*/		}catch (Exception e) {
			Log.e("info_airled", "Exception i:"+i);
			Log.e("info_airled", "Exception j:"+j);
		} 
		finally {
			if (canvas != null) {
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
	
	}
	
	/**
	 * 获取输入文字的矩阵
	 * 
	 * @return
	 */
	public List<short[]> genActualMatrixShortList(){
		actualMatrix = new short[byteList.size()*matrixSize][matrixSize];
		short[] singleLine = new short[matrixSize];
		List<short[]> actualMatrixList = new ArrayList<short[]>();
		for (int t = 0; t < byteList.size() ; t++) {
			for (int i = 0; i < matrixSize; i++) {
				for (int j = 0; j < 2; j++) {
					for (int k = 0; k < 8; k++) {
						try {
							if(((byteList.get(t)[i*2+j])&(0x80>>k))>=1){
								actualMatrix[t*matrixSize+j*8+k][i]=1;
							}else {
								actualMatrix[t*matrixSize+j*8+k][i]=0;
							}
						} catch (Exception e) {
							Log.i("info_airled", "byteList.get(t).length:"+byteList.get(t).length);
							e.printStackTrace();
							return null;
						}
					}
				}
			}
		}
		for (int i = 0; i < byteList.size()*matrixSize; i++) {
			for (int j = 0; j < matrixSize; j++) {
				if (actualMatrix[i][j]==1) {
					singleLine[j]=1;
				}else {
					singleLine[j]=0;
				}
			}
			actualMatrixList.add(singleLine.clone());
		}
		return actualMatrixList;
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		
	}

	Canvas canvas =null;
	public boolean isRun =false;
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Log.i("surfaceVew", "surfaceview created");
		isRun=true;
//		mt = new MyThread(holder);
//		mt.start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.i("surfaceVew", "surfaceview Destroyed");
	}
	
	public void repaint() {
		try {
			canvas = surfaceHolder.lockCanvas();
			for (int i = 0; i < xCount; i++) {
       			for (int j = 0; j < matrixSize; j++) {
       				if (ScreenMatrix[i][j] == 0) {
       					canvas.drawBitmap(GridBitMap[ScreenMatrix[i][j]], xOffset + i * gridSize , j * gridSize, paint);
       				}else if (ScreenMatrix[i][j] != 0) {
       					canvas.drawCircle(xOffset + gridSize/2 + i * gridSize, j * gridSize+gridSize/2, gridSize/2, textPaint);
       					canvas.drawBitmap(GridBitMap[ScreenMatrix[i][j]], xOffset + i * gridSize , j * gridSize, paint);
       				}
       			}
       		}
		} finally {
			if (canvas != null) {
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
	}
	
	public void processCmd(Long scrollOffset, int orientation) {
		actualMatrix2singleLed(scrollOffset, orientation);
	 }
	
	public void actualMatrix2singleLed(Long scrollOffset, int orientation) {
		int xScroll = (int) (scrollOffset % (byteList.size() * matrixSize));// 横向移动个数
		int midx = xOffset + (xCount / 2) * gridSize;
		Rect lockRect = new Rect(midx, 0, midx + gridSize, this.getHeight());
		try {
			canvas = surfaceHolder.lockCanvas(lockRect);
			canvas.drawColor(Color.BLACK);
			for (int j = 0; j < matrixSize; j++) {
				if (actualMatrix[xScroll][j] == 0) {
					// canvas.drawBitmap(GridBitMap[actualMatrix[i][j]], xOffset + (i+xCount-xScroll-1) * gridSize , j * gridSize, paint);
				} else if (actualMatrix[xScroll][j] != 0) {
					canvas.drawCircle(xOffset + (xCount / 2) * gridSize + gridSize / 2, j * gridSize + gridSize / 2, gridSize / 2, textPaint);
					canvas.drawBitmap(GridBitMap[actualMatrix[xScroll][j]], xOffset + (xCount / 2) * gridSize, j * gridSize, paint);
				}
			}
		} catch (Exception e) {
			Log.e("info_airled", "j:");
		} finally {
			if (canvas != null) {
				surfaceHolder.unlockCanvasAndPost(canvas);
			}
		}
	}



	
}
